﻿package frEngine.shader
{
    import __AS3__.vec.*;
    import baseEngine.basic.*;
    import baseEngine.system.*;
    import com.gengine.global.*;
    import com.gengine.resource.mutiThread.*;
    import flash.display3D.*;
    import flash.events.*;
    import flash.utils.*;
    import frEngine.*;
    import frEngine.event.*;
    import frEngine.manager.*;
    import frEngine.multiThread.*;
    import frEngine.multiThread.vo.*;
    import frEngine.shader.registType.*;
    import frEngine.shader.registType.base.*;

    public class Program3dRegisterInstance extends EventDispatcher
    {
        private var VHasUseNum:int = 0;
        private var VCHasUseNum_Vertex:int = 0;
        private var VCHasUseNum_Fragment:int = 0;
        private var VAHasUseNum:int = 0;
        private var FsHasUseNum:int = 0;
        public var VtHasUseNum:int = 0;
        public var FtHasUseNum:int = 0;
        public var program:Program3D;
        public var VparamList:Dictionary;
        public var FparamList:Dictionary;
        public var VcParamsConstList:Vector.<VcParam>;
        public var FcParamsConstList:Vector.<FcParam>;
        public var VaParamsList:Vector.<VaParam>;
        public var paramsMaxtrixList:Vector.<MaxtrixParam>;
        public var textures:Vector.<FsParam>;
        public var OpType:int = 4;
        private var _programeId:String;
        private var _repeat:Boolean;
        private var _cloneInstance:Program3dRegisterInstance;
        private var _hasAssembler:Boolean = false;
        private var _builder:Program3DBuilder;
        private var _vertexBytes:ByteArray;
        private var _fragBytes:ByteArray;
        private var _tmpVertexString:String;
        private var _tmpFragString:String;
        public var needCheckToUpload:Boolean = true;

        public function Program3dRegisterInstance(param1:String, param2:Program3dRegisterInstance = null)
        {
            this.VparamList = new Dictionary(false);
            this.FparamList = new Dictionary(false);
            this.VcParamsConstList = new Vector.<VcParam>;
            this.FcParamsConstList = new Vector.<FcParam>;
            this.VaParamsList = new Vector.<VaParam>;
            this.paramsMaxtrixList = new Vector.<MaxtrixParam>;
            this.textures = new Vector.<FsParam>;
            this._builder = new Program3DBuilder();
            this._programeId = param1;
            if (param2)
            {
                this.cloneFrom(param2);
            }
            return;
        }// end function

        public function get vertexBytes() : ByteArray
        {
            return this._vertexBytes;
        }// end function

        public function get fragBytes() : ByteArray
        {
            return this._fragBytes;
        }// end function

        public function reUpload() : void
        {
            var _loc_1:Object = null;
            var _loc_2:Program3D = null;
            if (this.program)
            {
                this.program.dispose();
                this.program = null;
                _loc_1 = Program3dManager.instance.getProgram3d(this.programeId, this._repeat);
                if (_loc_1)
                {
                    this.needCheckToUpload = false;
                    _loc_2 = this.impUpload(_loc_1.vertexBytes, _loc_1.fragBytes, null, _loc_1.program);
                    var _loc_3:* = _loc_2;
                    _loc_1.program = _loc_2;
                }
                else if (this._vertexBytes && this._fragBytes)
                {
                    this.impUpload(this._vertexBytes, this._fragBytes);
                }
            }
            return;
        }// end function

        public function get hasAssembler() : Boolean
        {
            if (this._cloneInstance)
            {
                return this._cloneInstance.hasAssembler;
            }
            return this._hasAssembler;
        }// end function

        public function get programeId() : String
        {
            return this._programeId;
        }// end function

        public function dispose() : void
        {
            this.needCheckToUpload = true;
            this.VparamList = null;
            this.FparamList = null;
            this.VaParamsList = null;
            this.VcParamsConstList = null;
            this.FcParamsConstList = null;
            this.paramsMaxtrixList = null;
            this._builder.callBackFun = null;
            this._builder = null;
            this.textures = null;
            this.VHasUseNum = 0;
            this.VCHasUseNum_Vertex = 0;
            this.VCHasUseNum_Fragment = 0;
            this.VAHasUseNum = 0;
            this.VtHasUseNum = 0;
            this.FtHasUseNum = 0;
            this.FsHasUseNum = 0;
            this._vertexBytes = null;
            this._fragBytes = null;
            if (this._cloneInstance != null)
            {
                FrEventDispatcher.instance.proxyRemoveEventListener(this._cloneInstance, Engine3dEventName.CONTEXT_REUPLOAD, this.resetProgramHander);
                this._cloneInstance = null;
            }
            return;
        }// end function

        public function upload(param1:Scene3D, param2:String, param3:String, param4:Boolean) : void
        {
            var _loc_6:Program3D = null;
            this._repeat = param4;
            var _loc_5:* = Program3dManager.instance.getProgram3d(this.programeId, this._repeat);
            if (_loc_5)
            {
                this.needCheckToUpload = false;
                _loc_6 = this.impUpload(_loc_5.vertexBytes, _loc_5.fragBytes, null, _loc_5.program);
                var _loc_7:* = _loc_6;
                _loc_5.program = _loc_6;
            }
            else
            {
                this.toBuidResult(param2, param3);
            }
            return;
        }// end function

        public function toBuild(param1:String, param2:Array) : String
        {
            var _loc_4:int = 0;
            var _loc_5:RegExp = null;
            var _loc_6:* = undefined;
            var _loc_8:ToBuilderInfo = null;
            var _loc_3:* = param2.length;
            var _loc_7:int = 0;
            while (_loc_7 < _loc_3)
            {
                
                _loc_8 = param2[_loc_7];
                this.registParam(_loc_8);
                _loc_5 = new RegExp(_loc_8.oldVarName, "gi");
                param1 = param1.replace(_loc_5, _loc_8.paramName);
                _loc_7++;
            }
            return param1;
        }// end function

        public function getParamByName(param1:String, param2:Boolean)
        {
            if (param1.indexOf("{") != 0 || param1.indexOf("}") != (param1.length - 1))
            {
                throw new Error("名称不合法，请加上{}");
            }
            if (param2)
            {
                return this.VparamList[param1];
            }
            return this.FparamList[param1];
        }// end function

        private function toBuidResult(param1:String, param2:String) : void
        {
            var _loc_5:String = null;
            var _loc_6:Object = null;
            var _loc_3:* = new Dictionary(false);
            var _loc_4:* = new Dictionary(false);
            for (_loc_5 in this.VparamList)
            {
                
                _loc_3[_loc_5] = this.VparamList[_loc_5].registName;
            }
            for (_loc_5 in this.FparamList)
            {
                
                _loc_4[_loc_5] = this.FparamList[_loc_5].registName;
            }
            this._tmpVertexString = param1;
            this._tmpFragString = param2;
            if (Global.threadManager && !Global3D.isOpenGL)
            {
                this.needCheckToUpload = false;
                _loc_6 = {transType:ThreadTransType.AgalBuild, vertexCode:param1, fragmentCode:param2, VparamList:_loc_3, FparamList:_loc_4, VtHasUseNum:this.VtHasUseNum, FtHasUseNum:this.FtHasUseNum};
                F3DThreadManager.instance.sendMessageToSub(_loc_6, this.threadCallBack);
            }
            else
            {
                this.needCheckToUpload = true;
                this._builder.callBackFun = this.impUpload;
                this._builder.buildByNormal(param1, param2, _loc_3, _loc_4, this.VtHasUseNum, this.FtHasUseNum);
            }
            return;
        }// end function

        private function threadCallBack(param1:AgalVo) : void
        {
            param1.vertexBytes.endian = Endian.LITTLE_ENDIAN;
            param1.fragBytes.endian = Endian.LITTLE_ENDIAN;
            this.impUpload(param1.vertexBytes, param1.fragBytes, param1.sourceCode);
            return;
        }// end function

        private function impUpload(param1:ByteArray, param2:ByteArray, param3:String = null, param4:Program3D = null) : Program3D
        {
            var vertexBytes:* = param1;
            var fragBytes:* = param2;
            var sourceCode:* = param3;
            var $program:* = param4;
            this._vertexBytes = vertexBytes;
            this._fragBytes = fragBytes;
            try
            {
                if ($program != null)
                {
                    this.program = $program;
                    FrEventDispatcher.instance.proxyDispatchEvent(this, Engine3dEventName.CONTEXT_REUPLOAD);
                    this._hasAssembler = true;
                }
                else
                {
                    if (!this.program)
                    {
                        this.program = Global3D.scene.context.createProgram();
                    }
                    this.program.upload(vertexBytes, fragBytes);
                    FrEventDispatcher.instance.proxyDispatchEvent(this, Engine3dEventName.CONTEXT_REUPLOAD);
                    this._hasAssembler = true;
                }
            }
            catch (e:Error)
            {
                if (e.errorID == 3694 || e.errorID == 1009)
                {
                    Global3D.scene.reUploadHander(true);
                }
                else
                {
                    trace("upload Error message:", e.message, sourceCode);
                    trace("vertexCode:", _tmpVertexString);
                    trace("fragCode:", _tmpFragString);
                }
            }
            return this.program;
        }// end function

        public function assemblerGoOn(param1:Number) : void
        {
            this._builder.assemblerGoOn(true, param1);
            return;
        }// end function

        private function getFreeV(param1:int) : int
        {
            var _loc_2:* = this.VHasUseNum;
            this.VHasUseNum = this.VHasUseNum + param1;
            return _loc_2;
        }// end function

        private function getFreeVc(param1:int) : int
        {
            var _loc_2:* = this.VCHasUseNum_Vertex;
            this.VCHasUseNum_Vertex = this.VCHasUseNum_Vertex + param1;
            return _loc_2;
        }// end function

        private function getFreeFc(param1:int) : int
        {
            var _loc_2:* = this.VCHasUseNum_Fragment;
            this.VCHasUseNum_Fragment = this.VCHasUseNum_Fragment + param1;
            return _loc_2;
        }// end function

        private function getFreeVt(param1:int) : int
        {
            var _loc_2:* = this.VtHasUseNum;
            this.VtHasUseNum = this.VtHasUseNum + param1;
            return _loc_2;
        }// end function

        private function getFreeFs(param1:int) : int
        {
            var _loc_2:* = this.FsHasUseNum;
            this.FsHasUseNum = this.FsHasUseNum + param1;
            return _loc_2;
        }// end function

        private function getFreeFt(param1:int) : int
        {
            var _loc_2:* = this.FtHasUseNum;
            this.FtHasUseNum = this.FtHasUseNum + param1;
            return _loc_2;
        }// end function

        private function getFreeVA(param1:int) : int
        {
            var _loc_2:* = this.VAHasUseNum;
            this.VAHasUseNum = this.VAHasUseNum + param1;
            return _loc_2;
        }// end function

        public function registParam(param1:ToBuilderInfo) : void
        {
            var _loc_3:int = 0;
            var _loc_4:RegistParam = null;
            var _loc_6:* = undefined;
            var _loc_7:String = null;
            var _loc_2:* = param1.paramName;
            if (this.getParamByName(_loc_2, param1.isVertex))
            {
                return;
            }
            var _loc_5:* = param1.isVertex;
            if (param1.isGlobleVar)
            {
                _loc_6 = Device3D[_loc_2.substr(1, _loc_2.length - 2)];
            }
            else
            {
                _loc_6 = param1.defaultValue;
            }
            switch(param1.type)
            {
                case "va":
                {
                    _loc_3 = this.getFreeVA(1);
                    _loc_4 = new VaParam(_loc_3, "float" + param1.varNum, _loc_2);
                    break;
                }
                case "vc":
                {
                    _loc_3 = this.getFreeVc(param1.varNum);
                    _loc_4 = new VcParam(_loc_3, _loc_2, _loc_6);
                    break;
                }
                case "fc":
                {
                    _loc_3 = this.getFreeFc(param1.varNum);
                    _loc_4 = new FcParam(_loc_3, _loc_2, _loc_6);
                    break;
                }
                case "fm":
                case "vm":
                {
                    if (_loc_5)
                    {
                        _loc_3 = this.getFreeVc(4);
                        _loc_7 = Context3DProgramType.VERTEX;
                    }
                    else
                    {
                        _loc_3 = this.getFreeFc(4);
                        _loc_7 = Context3DProgramType.FRAGMENT;
                    }
                    _loc_4 = new MaxtrixParam(_loc_7, _loc_3, _loc_2, _loc_6);
                    break;
                }
                case "v":
                {
                    _loc_3 = this.getFreeV(1);
                    _loc_4 = new Vparam(_loc_2, _loc_3);
                    this.registParamName(_loc_2, _loc_4, false, "v");
                    break;
                }
                case "vt":
                {
                    _loc_3 = this.getFreeVt(param1.varNum);
                    _loc_4 = new VtParam(_loc_2, _loc_3);
                    break;
                }
                case "ft":
                {
                    _loc_3 = this.getFreeFt(param1.varNum);
                    _loc_4 = new FtParam(_loc_2, _loc_3);
                    break;
                }
                case "fs":
                {
                    _loc_3 = this.getFreeFs(param1.varNum);
                    _loc_4 = new FsParam(_loc_3, _loc_2, _loc_6);
                    break;
                }
                default:
                {
                    break;
                }
            }
            this.registParamName(_loc_2, _loc_4, _loc_5, param1.type);
            return;
        }// end function

        public function cloneFrom(param1:Program3dRegisterInstance) : void
        {
            this._cloneInstance = param1;
            this.program = param1.program;
            this._programeId = param1._programeId;
            this.OpType = param1.OpType;
            this.copyVcParams(param1.VcParamsConstList);
            this.copyFcParams(param1.FcParamsConstList);
            this.copyMaxtrixList(param1.paramsMaxtrixList);
            this.copyTextureList(param1.textures);
            this.copyVaList(param1.VaParamsList);
            this._hasAssembler = param1._hasAssembler;
            this.VHasUseNum = param1.VHasUseNum;
            this.VCHasUseNum_Vertex = param1.VCHasUseNum_Vertex;
            this.VCHasUseNum_Fragment = param1.VCHasUseNum_Fragment;
            this.VAHasUseNum = param1.VAHasUseNum;
            this.VtHasUseNum = param1.VtHasUseNum;
            this.FtHasUseNum = param1.FtHasUseNum;
            this.FsHasUseNum = param1.FsHasUseNum;
            FrEventDispatcher.instance.proxyAddEventListener(param1, Engine3dEventName.CONTEXT_REUPLOAD, this.resetProgramHander);
            return;
        }// end function

        private function resetProgramHander(event:Event) : void
        {
            var _loc_2:* = event.currentTarget as Program3dRegisterInstance;
            this.program = _loc_2.program;
            FrEventDispatcher.instance.proxyDispatchEvent(this, Engine3dEventName.CONTEXT_REUPLOAD);
            return;
        }// end function

        private function copyVaList(param1:Vector.<VaParam>) : void
        {
            var _loc_5:VaParam = null;
            var _loc_2:* = param1.length;
            var _loc_3:* = this.VaParamsList;
            var _loc_4:int = 0;
            while (_loc_4 < _loc_2)
            {
                
                _loc_5 = param1[_loc_4].clone();
                _loc_3.push(_loc_5);
                this.VparamList[_loc_5.paramName] = _loc_5;
                _loc_4++;
            }
            return;
        }// end function

        private function copyTextureList(param1:Vector.<FsParam>) : void
        {
            var _loc_5:FsParam = null;
            var _loc_2:* = param1.length;
            var _loc_3:* = this.textures;
            var _loc_4:int = 0;
            while (_loc_4 < _loc_2)
            {
                
                _loc_5 = param1[_loc_4].clone();
                _loc_3.push(_loc_5);
                this.FparamList[_loc_5.paramName] = _loc_5;
                _loc_4++;
            }
            return;
        }// end function

        private function copyMaxtrixList(param1:Vector.<MaxtrixParam>) : void
        {
            var _loc_5:MaxtrixParam = null;
            var _loc_2:* = param1.length;
            var _loc_3:* = this.paramsMaxtrixList;
            var _loc_4:int = 0;
            while (_loc_4 < _loc_2)
            {
                
                _loc_5 = param1[_loc_4].clone();
                _loc_3.push(_loc_5);
                if (_loc_5.type == Context3DProgramType.FRAGMENT)
                {
                    this.FparamList[_loc_5.paramName] = _loc_5;
                }
                else
                {
                    this.VparamList[_loc_5.paramName] = _loc_5;
                }
                _loc_4++;
            }
            return;
        }// end function

        private function copyFcParams(param1:Vector.<FcParam>) : void
        {
            var _loc_5:FcParam = null;
            var _loc_2:* = param1.length;
            var _loc_3:* = this.FcParamsConstList;
            var _loc_4:int = 0;
            while (_loc_4 < _loc_2)
            {
                
                _loc_5 = param1[_loc_4].clone();
                _loc_3.push(_loc_5);
                this.FparamList[_loc_5.paramName] = _loc_5;
                _loc_4++;
            }
            return;
        }// end function

        private function copyVcParams(param1:Vector.<VcParam>) : void
        {
            var _loc_5:VcParam = null;
            var _loc_2:* = param1.length;
            var _loc_3:* = this.VcParamsConstList;
            var _loc_4:int = 0;
            while (_loc_4 < _loc_2)
            {
                
                _loc_5 = param1[_loc_4].clone();
                _loc_3.push(_loc_5);
                this.VparamList[_loc_5.paramName] = _loc_5;
                _loc_4++;
            }
            return;
        }// end function

        private function registParamName(param1:String, param2:RegistParam, param3:Boolean, param4:String) : void
        {
            if (param3)
            {
                if (this.VparamList[param1])
                {
                    throw new Error("已注册顶点寄存器名称：" + param1);
                }
                this.VparamList[param1] = param2;
            }
            else
            {
                if (this.FparamList[param1])
                {
                    throw new Error("已注册片段寄存器名称：" + param1);
                }
                this.FparamList[param1] = param2;
            }
            switch(param4)
            {
                case "va":
                {
                    this.VaParamsList.push(param2);
                    break;
                }
                case "vc":
                {
                    this.VcParamsConstList.push(param2);
                    break;
                }
                case "fc":
                {
                    this.FcParamsConstList.push(param2);
                    break;
                }
                case "fm":
                case "vm":
                {
                    this.paramsMaxtrixList.push(param2);
                    break;
                }
                case "fs":
                {
                    this.textures.push(param2);
                    break;
                }
                default:
                {
                    break;
                }
            }
            return;
        }// end function

    }
}
